﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace SmokinAces.Object_Classes.Objects
{
    public enum NPC_Type { NPC1 = 1, NPC2 = 2, NPC3 = 3 };
    public class NPC : Game_Object, Draw_Object, Logic_Object
    {
        //------this is information for the editor...
        static Type[] constructor_parameters = { typeof(int), typeof(int), typeof(NPC_Type), typeof(Main_Engine) };
        static object[] default_const_values = { 0, 0, NPC_Type.NPC1, null };
        //------------------------------------
        int NPCIndex;
        private Sort_Delegate drawSortDelegate;
        VertexPositionColorTexture[] baseImage;
        VertexPositionColorTexture[] vertecies;
        int[] indecies;
        const float zorder = 1.0f;
        private const float divider = 1.0f / 14;

        private NPC_Type _currentNPC;
        public NPC_Type currentNPC
        {
            get { return _currentNPC; }
            set
            {
                _currentNPC = value;
                this.NPCIndex = parent.register_texture("\\Sprites\\NPC\\npc" + ((int)_currentNPC) + ".png");
            }
        }
        public NPC(XmlReader xmlReader, Main_Engine Parent)
        {
            xmlReader.Read();
            string sLeft = xmlReader.ReadElementString("Left");
            string sTop = xmlReader.ReadElementString("Top");
            string sNPCType = xmlReader.ReadElementString("NPC_Type");
            //------------------------------------
            int left = Convert.ToInt32(sLeft);
            int top = Convert.ToInt32(sTop);
            NPC_Type NPCType = (NPC_Type)Enum.Parse(typeof(NPC_Type),sNPCType);
            Initialize(left, top, left + 48, top + 80, NPCType, Parent);
        }
        public override bool Save_XML(XmlTextWriter textWriter)
        {
            try
            {
                textWriter.WriteStartElement("Game_Object");
                textWriter.WriteAttributeString("Type", this.GetType().AssemblyQualifiedName);
                textWriter.WriteElementString("Left", baseImage[0].Position.X.ToString());
                textWriter.WriteElementString("Top", baseImage[0].Position.Y.ToString());
                textWriter.WriteElementString("NPC_Type", Enum.GetName(typeof(NPC_Type), _currentNPC));
                textWriter.WriteEndElement();
                textWriter.Flush();
            }
            catch
            {
                return false;
            }
            return true;
        }
        public NPC(int left, int top, Main_Engine parent)
        {
            Initialize(left, top, left + 48, top + 80, NPC_Type.NPC1, parent);
        }
        public NPC(int left, int top, NPC_Type NPC, Main_Engine parent)
        {
            Initialize(left, top, left + 48, top + 80, NPC, parent);
        }
        private void Initialize(int left, int top, int right, int bottom, NPC_Type NPC, Main_Engine parent)
        {
            this.parent = parent;
            GraphicBB = new BoundingBox(new Vector3(left, top, Util.MinZ), new Vector3(right, bottom, Util.MaxZ));
            this.currentNPC = NPC;
            Color baseColor = new Color(255, 255, 255, 255);
            //color = baseColor;
            baseImage = new VertexPositionColorTexture[4];
            baseImage[0].Position = new Vector3(left, top, zorder);
            baseImage[0].Color = baseColor;
            baseImage[0].TextureCoordinate = new Vector2(divider, 0.99f);
            baseImage[1].Position = new Vector3(left, bottom, zorder);
            baseImage[1].Color = baseColor;
            baseImage[1].TextureCoordinate = new Vector2(divider, 0.0f);
            baseImage[2].Position = new Vector3(right, top, zorder);
            baseImage[2].Color = baseColor;
            baseImage[2].TextureCoordinate = new Vector2(0.0f, 0.99f);
            baseImage[3].Position = new Vector3(right, bottom, zorder);
            baseImage[3].Color = baseColor;
            baseImage[3].TextureCoordinate = new Vector2(0.0f, 0.0f);

            vertecies = Util.ComplexMesh(baseImage, out indecies, 4, 4);
            Bounding_Regions.Add(new BoundingBox(new Vector3(left + 10, top + 0, -1), new Vector3(left + 38, top + 17, 1)));
            drawSortDelegate = new Sort_Delegate(((1024 - top) * 1024) + left, Draw);
        }

        #region Draw_Object Members

        public void Draw(GameTime gameTime, GraphicsDevice device)
        {

            //---Set the Texture for this layer
            parent.effect.BaseTexture = parent.Texture_List[NPCIndex];
            //---------Begin the drawing passes
            parent.effect.Begin();
            foreach (EffectPass pass in parent.effect.CurrentTechnique.Passes)
            {
                pass.Begin();
                //device.DrawUserPrimitives(PrimitiveType.TriangleStrip, baseImage, 0, 2);
                device.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertecies, 0, vertecies.Length, indecies, 0, indecies.Length / 3);
                pass.End();
            }
            parent.effect.End();
        }
        public bool startDraw()
        {
            parent.Draw_Functions[3].Add(drawSortDelegate);
            return true;
        }
        public bool stopDraw()
        {
            parent.Draw_Functions[3].Remove(drawSortDelegate);
            return true;
        }
        #endregion

        #region Game_Object Members

        public override bool dispose()
        {
            //----------------I used some basic boolean logic here...
            stopDraw();
            return parent.Draw_Functions[3].Remove(drawSortDelegate);
        }
        #endregion
        
        #region Logic_Object Members
        int loop = 1;
        double LastAnimation = 0.0;
        int update = 60;
        int[] SouthAnimationList = { 2, 1, 1, 1, 2, 2, 2, 3, 3, 3, 2, 2 };
        int[] NorthAnimationList = { 5, 4, 4, 4, 5, 5, 5, 6, 6, 6, 5, 5 };
        int[] WestAnimationList = { 9, 8, 7, 7, 8, 9, 9, 10, 10, 10, 8, 9 };
        int[] EastAnimationList = { 13, 12, 11, 11, 12, 13, 13, 14, 14, 14, 12, 13 };
        int distance = 0;
        Vector3 Speed = Vector3.Zero;
        /*
        int x;
        int y;*/
        int direction = 0;
        static Random rand = new Random(17);
        public void Update(GameTime gameTime)
        {
            if (gameTime.TotalGameTime.TotalMilliseconds > LastAnimation + update)
            {
                LastAnimation = gameTime.TotalGameTime.TotalMilliseconds;
                
                if (distance == 0)
                {

                    direction = rand.Next(0, 4);
                    distance = rand.Next(20, 50);
                    if (direction == 0)
                    {
                        Speed.X = 4;
                        Speed.Y = 0;
                    }
                    else if(direction == 1)  
                    {
                        Speed.X = -4;
                        Speed.Y = 0;
                    }
                    else if(direction == 2)  
                    {
                        Speed.X = 0;
                        Speed.Y = 4;
                    }
                    else if (direction == 3)
                    {
                        Speed.X = 0;
                        Speed.Y = -4;
                    }

                    int xOffset = 0;
                    int yOffset = 0;
                    if (direction == 0)
                    {
                        yOffset = 0;
                        xOffset = 40;
                    }
                    else if (direction == 1)
                    {
                        yOffset = 0;
                        xOffset = -40;
                    }
                    else if (direction == 2)
                    {
                        yOffset = +60;
                        xOffset = 0;
                    }
                    else if (direction == 3)
                    {
                        yOffset = -70;
                        xOffset = 0;
                        
                    }
                        Fireball fireBall = new Fireball((int)((GraphicBB.Max.X - GraphicBB.Min.X) / 2.0f + GraphicBB.Min.X) + xOffset, (int)((GraphicBB.Max.Y - GraphicBB.Min.Y) / 2.0f + GraphicBB.Min.Y) + yOffset, parent);
                        fireBall.direction = direction;
                        parent.MapObjects.Add(fireBall);
                    //-------------------------------
                    
                    
                }
                distance--;
                loop++;
                if (loop > 11)
                {
                    loop = 0;
                }

                switch (direction)
                {
                    case 0:
                        recalculate(EastAnimationList);
                        break;
                    case 1:
                        recalculate(WestAnimationList);
                        break;
                    case 2:
                        recalculate(NorthAnimationList);
                        break;
                    case 3:
                        recalculate(SouthAnimationList);
                        break;
                }
            }
        }
        bool alive = true;
        private void recalculate(int[] AnimationList)
        {
            float offset = AnimationList[loop] * divider;
            if (this.isColliding())
            {
                HashSet<Game_Object> crash = this.isCollidingWith(Bounding_Regions[0], Collision_Type.Weapon);
                if (crash.OfType<Fireball>().Count() > 0 || crash.OfType<IceBolt>().Count() > 0)
                {
                    SoundManager.PlaySound("Death");
                    alive = false;
                }
                if (crash.OfType<Main_Character>().Count() > 0)
                {
                    SoundManager.PlaySound("Death");
                    alive = false;
                }
            }
            else
            {
                updateBoundingRegions(Speed);
                if (this.isColliding())
                {
                    offset = AnimationList[0] * divider;
                    distance = 0;
                    updateBoundingRegions(-Speed);
                }
                else
                {
                    drawSortDelegate = new Sort_Delegate(((1024 - GraphicBB.Min.Y) * 1024) + GraphicBB.Min.X, Draw);
                    baseImage[0].Position += Speed;
                    baseImage[1].Position += Speed;
                    baseImage[2].Position += Speed;
                    baseImage[3].Position += Speed;
                    vertecies = Util.ComplexMesh(baseImage, out indecies, 4, 4);
                }
            }

                baseImage[0].TextureCoordinate = new Vector2(offset, 0.99f);
                baseImage[1].TextureCoordinate = new Vector2(offset, 0.0f);
                baseImage[2].TextureCoordinate = new Vector2(offset - divider, 0.99f);
                baseImage[3].TextureCoordinate = new Vector2(offset - divider, 0.0f);

                vertecies = Util.ComplexMesh(baseImage, out indecies, 4, 4);

                //------------This is to update the quadtree
                parent.MapObjects.Remove(this);
                if (alive)
                {
                    parent.MapObjects.Add(this);
                }
                //-------------------------------------------
        }

        public bool stopUpdate()
        {
            parent.remove_Update_Object(Update);
            return true;
        }

        public bool startUpdate()
        {
            parent.add_Update_Object(Update);
            return true;
        }

        #endregion
    }
}
